﻿using System;
using System.Collections.Generic;
using System.Text;

namespace YYFUtils
{
    /// <summary>
    /// 时间戳转换
    /// </summary>
    public static class DateTimeHelper
    {
        private const long STANDARD_TIME_STAMP = 621355968000000000;

        /// <summary>
        /// 时间转换为时间戳
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static long ConvertToTimeStamp(this DateTime time)
        {
            return (time.ToUniversalTime().Ticks - STANDARD_TIME_STAMP) / 10000000;
        }

        /// <summary>
        ///  时间戳转换为时间
        /// </summary>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public static DateTime ConvertToDateTime(this long timestamp)
        {
            return new DateTime(timestamp * 10000000 + STANDARD_TIME_STAMP).ToLocalTime();
        }


        /// <summary>
        /// 根据日期获取星期几
        /// </summary>
        public static string GetWeekByDate(DateTime dt)
        {
            var day = new[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
            return day[Convert.ToInt32(dt.DayOfWeek.ToString("d"))];
        }

        /// <summary>
        /// 得到这个月的第几周
        /// </summary>
        /// <param name="daytime">年月日</param>
        /// <returns>传递过来的时间是第几周</returns>
        public static int GetWeekNumInMonth(DateTime daytime)
        {
            int dayInMonth = daytime.Day;
            //本月第一天
            DateTime firstDay = daytime.AddDays(1 - daytime.Day);
            //本月第一天是周几
            int weekday = (int)firstDay.DayOfWeek == 0 ? 7 : (int)firstDay.DayOfWeek;
            //本月第一周有几天
            int firstWeekEndDay = 7 - (weekday - 1);
            //当前日期和第一周之差
            int diffday = dayInMonth - firstWeekEndDay;
            diffday = diffday > 0 ? diffday : 1;
            //当前是第几周,如果整除7就减一天
            int weekNumInMonth = ((diffday % 7) == 0
                ? (diffday / 7 - 1)
                : (diffday / 7)) + 1 + (dayInMonth > firstWeekEndDay ? 1 : 0);
            return weekNumInMonth;
        }
        /// <summary>
        /// 获取耗时
        /// </summary>
        /// <param name="btime">开始时间</param>
        /// <param name="etime">结束时间 默认当前</param>
        /// <returns></returns>
        public static string GetTimeSpan(DateTime btime, DateTime? etime = null)
        {
            if (etime == null) etime = DateTime.Now;
            TimeSpan ts = etime.Value.Subtract(btime);
            var hs = $"耗时{(ts.Days == 0 ? "" : (ts.Days + "天 "))}{(ts.Hours == 0 ? "" : (ts.Hours + "小时 "))} {(ts.Minutes == 0 ? "" : (ts.Minutes + "分钟 "))} {(ts.Seconds == 0 ? "" : (ts.Seconds + "秒 "))} {ts.Milliseconds}毫秒 [{ts.TotalMilliseconds}ms]";
            return hs;
        }
    }

    /// <summary>
    /// 时间戳校验
    /// </summary>
    public static class TimestampWithCheck
    {
        /// <summary>
        /// 生成带校验位的18位时间戳
        /// </summary>
        /// <returns></returns>
        public static long GenerateTimestampWithCheck()
        {
            // 获取当前的18位时间戳
            long timestamp = DateTime.Now.Ticks;

            // 提取前17位时间戳
            long timestampWithoutCheck = timestamp / 10;

            // 计算校验位
            long checkBit = CalculateCheckBit(timestampWithoutCheck);

            // 拼接时间戳和校验位
            return timestampWithoutCheck * 10 + checkBit;
        }

        /// <summary>
        /// 校验位计算：取前17位各位数之和的个位数
        /// </summary>
        /// <param name="timestampWithoutCheck"></param>
        /// <returns></returns>
        private static long CalculateCheckBit(long timestampWithoutCheck)
        {
            long sum = 0;
            while (timestampWithoutCheck > 0)
            {
                sum += timestampWithoutCheck % 10;
                timestampWithoutCheck /= 10;
            }
            return sum % 10; // 取个位数作为校验位
        }

        /// <summary>
        /// 校验时间戳的有效性
        /// </summary>
        /// <param name="timestampWithCheck">待验证时间戳</param>
        /// <returns>校验是否通过</returns>
        public static bool ValidateTimestamp(long timestampWithCheck)
        {
            // 提取时间戳的前17位和校验位
            long timestampWithoutCheck = timestampWithCheck / 10;
            int providedCheckBit = (int)(timestampWithCheck % 10);

            // 计算正确的校验位
            long calculatedCheckBit = CalculateCheckBit(timestampWithoutCheck);

            // 校验时间戳的校验位是否正确
            return providedCheckBit == calculatedCheckBit;
        }
    }
}
